Android アプリに Flutter フラグメントを追加する
このガイドでは、Flutter を追加する方法について説明します。Fragment
既存のものに
アンドロイドアプリ。 Android では、Fragment
モジュラーを表します
より大きな UI の一部。あFragment
プレゼンテーションに使用されるかもしれません
スライド式ドロワー、タブ付きコンテンツ、ページ内のページViewPager
、
あるいは、単純に通常の画面を表す場合もあります。
独身-Activity
アプリ。 Flutter が提供するのは、FlutterFragment
開発者がどこでも Flutter エクスペリエンスを提供できるようにする
通常のを使用できることFragment
。
もしActivity
アプリケーションのニーズにも同様に適用できます。
検討を使ってFlutterActivity
の代わりにFlutterFragment
、より速くて使いやすいです。
FlutterFragment
開発者が以下を制御できるようにします
Flutter エクスペリエンスの詳細Fragment
:
- 初期 flutterルート
- 実行する Dart エントリポイント
- 不透明な背景と半透明の背景
- どうにか
FlutterFragment
周囲をコントロールする必要があるActivity
- 新しいかどうか
FlutterEngine
またはキャッシュされたFlutterEngine
使用すべきです
FlutterFragment
多くのコールも付属しています。
周囲から転送する必要があるActivity
。
これらの呼び出しにより、Flutter は OS イベントに適切に反応できるようになります。
全種類のFlutterFragment
、およびその要件、
については、このガイドで説明されています。
FlutterFragment
にActivity
新しいものでFlutterEngine
追加を使用するために最初に行うことは、FlutterFragment
それをホストに追加することですActivity
。
を追加するにはFlutterFragment
ホストにActivity
、インスタンス化して、
のインスタンスをアタッチしますFlutterFragment
のonCreate()
以内Activity
または、アプリに適した別のタイミングで次のようにします。
public class MyActivity extends FragmentActivity {
// Define a tag String to represent the FlutterFragment within this
// Activity's FragmentManager. This value can be whatever you'd like.
private static final String TAG_FLUTTER_FRAGMENT = "flutter_fragment";
// Declare a local variable to reference the FlutterFragment so that you
// can forward calls to it later.
private FlutterFragment flutterFragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Inflate a layout that has a container for your FlutterFragment.
// For this example, assume that a FrameLayout exists with an ID of
// R.id.fragment_container.
setContentView(R.layout.my_activity_layout);
// Get a reference to the Activity's FragmentManager to add a new
// FlutterFragment, or find an existing one.
FragmentManager fragmentManager = getSupportFragmentManager();
// Attempt to find an existing FlutterFragment,
// in case this is not the first time that onCreate() was run.
flutterFragment = (FlutterFragment) fragmentManager
.findFragmentByTag(TAG_FLUTTER_FRAGMENT);
// Create and attach a FlutterFragment if one does not exist.
if (flutterFragment == null) {
flutterFragment = FlutterFragment.createDefault();
fragmentManager
.beginTransaction()
.add(
R.id.fragment_container,
flutterFragment,
TAG_FLUTTER_FRAGMENT
)
.commit();
}
}
}
class MyActivity : FragmentActivity() {
companion object {
// Define a tag String to represent the FlutterFragment within this
// Activity's FragmentManager. This value can be whatever you'd like.
private const val TAG_FLUTTER_FRAGMENT = "flutter_fragment"
}
// Declare a local variable to reference the FlutterFragment so that you
// can forward calls to it later.
private var flutterFragment: FlutterFragment? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Inflate a layout that has a container for your FlutterFragment. For
// this example, assume that a FrameLayout exists with an ID of
// R.id.fragment_container.
setContentView(R.layout.my_activity_layout)
// Get a reference to the Activity's FragmentManager to add a new
// FlutterFragment, or find an existing one.
val fragmentManager: FragmentManager = supportFragmentManager
// Attempt to find an existing FlutterFragment, in case this is not the
// first time that onCreate() was run.
flutterFragment = fragmentManager
.findFragmentByTag(TAG_FLUTTER_FRAGMENT) as FlutterFragment?
// Create and attach a FlutterFragment if one does not exist.
if (flutterFragment == null) {
var newFlutterFragment = FlutterFragment.createDefault()
flutterFragment = newFlutterFragment
fragmentManager
.beginTransaction()
.add(
R.id.fragment_container,
newFlutterFragment,
TAG_FLUTTER_FRAGMENT
)
.commit()
}
}
}
Flutter UI をレンダリングするには、前のコードで十分です。
それはあなたへの電話から始まりますmain()
ダーツのエントリーポイント、
の初期 Flutter ルート/
、そして新しいFlutterEngine
。
ただし、このコードは期待されるすべてのことを達成するには十分ではありません。
flutter動作。 flutterはさまざまな OS 信号に依存します。
ホストから転送する必要がありますActivity
にFlutterFragment
。
これらの呼び出しを次の例に示します。
public class MyActivity extends FragmentActivity {
@Override
public void onPostResume() {
super.onPostResume();
flutterFragment.onPostResume();
}
@Override
protected void onNewIntent(@NonNull Intent intent) {
flutterFragment.onNewIntent(intent);
}
@Override
public void onBackPressed() {
flutterFragment.onBackPressed();
}
@Override
public void onRequestPermissionsResult(
int requestCode,
@NonNull String[] permissions,
@NonNull int[] grantResults
) {
flutterFragment.onRequestPermissionsResult(
requestCode,
permissions,
grantResults
);
}
@Override
public void onUserLeaveHint() {
flutterFragment.onUserLeaveHint();
}
@Override
public void onTrimMemory(int level) {
super.onTrimMemory(level);
flutterFragment.onTrimMemory(level);
}
}
class MyActivity : FragmentActivity() {
override fun onPostResume() {
super.onPostResume()
flutterFragment!!.onPostResume()
}
override fun onNewIntent(@NonNull intent: Intent) {
flutterFragment!!.onNewIntent(intent)
}
override fun onBackPressed() {
flutterFragment!!.onBackPressed()
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String?>,
grantResults: IntArray
) {
flutterFragment!!.onRequestPermissionsResult(
requestCode,
permissions,
grantResults
)
}
override fun onUserLeaveHint() {
flutterFragment!!.onUserLeaveHint()
}
override fun onTrimMemory(level: Int) {
super.onTrimMemory(level)
flutterFragment!!.onTrimMemory(level)
}
}
OS シグナルが Flutter に転送されると、
あなたのFlutterFragment
期待通りに動作します。
これで、FlutterFragment
既存の Android アプリに追加します。
最も単純な統合パスでは、新しいFlutterEngine
、
これにはかなりの初期化時間がかかりますが、
Flutter が有効になるまで、空白の UI が表示されます。
初めて初期化されてレンダリングされます。
ほとんどの場合、オーバーヘッドは次の方法で回避できます。
キャッシュされ、事前にウォームアップされたFlutterEngine
、これについては次に説明します。
FlutterEngine
あらかじめ温めたものを使用するデフォルトでは、FlutterFragment
独自のインスタンスを作成する
のFlutterEngine
、これにはかなりのウォームアップ時間が必要です。
これは、ユーザーには空白が表示されることを意味しますFragment
ほんの一瞬の間。
このウォームアップ時間のほとんどは、次の方法で軽減できます。
既存の事前にウォームアップされたインスタンスを使用するFlutterEngine
。
あらかじめ温めたものを使用するにはFlutterEngine
でFlutterFragment
、
をインスタンス化するFlutterFragment
とともにwithCachedEngine()
ファクトリーメソッド。
// Somewhere in your app, before your FlutterFragment is needed,
// like in the Application class ...
// Instantiate a FlutterEngine.
FlutterEngine flutterEngine = new FlutterEngine(context);
// Start executing Dart code in the FlutterEngine.
flutterEngine.getDartExecutor().executeDartEntrypoint(
DartEntrypoint.createDefault()
);
// Cache the pre-warmed FlutterEngine to be used later by FlutterFragment.
FlutterEngineCache
.getInstance()
.put("my_engine_id", flutterEngine);
FlutterFragment.withCachedEngine("my_engine_id").build();
// Somewhere in your app, before your FlutterFragment is needed,
// like in the Application class ...
// Instantiate a FlutterEngine.
val flutterEngine = FlutterEngine(context)
// Start executing Dart code in the FlutterEngine.
flutterEngine.getDartExecutor().executeDartEntrypoint(
DartEntrypoint.createDefault()
)
// Cache the pre-warmed FlutterEngine to be used later by FlutterFragment.
FlutterEngineCache
.getInstance()
.put("my_engine_id", flutterEngine)
FlutterFragment.withCachedEngine("my_engine_id").build()
FlutterFragment
内部的には知っているFlutterEngineCache
事前に温めたものを取り出しますFlutterEngine
IDに基づいて
与えられたwithCachedEngine()
。
あらかじめ温めたものを提供することで、FlutterEngine
、
前に示したように、アプリは
最初の Flutter フレームをできるだけ早く実行します。
キャッシュされたエンジンを使用した初期ルート
初期ルートの概念は、FlutterActivity
またはFlutterFragment
新しいものでFlutterEngine
。
しかし、FlutterActivity
とFlutterFragment
を提供しないでください
キャッシュされたエンジンを使用する場合の初期ルートの概念。
これは、キャッシュされたエンジンがすでに存在していることが想定されるためです。
Dart コードを実行しているため、設定するには遅すぎることを意味します。
初期ルート。
キャッシュされたエンジンを起動したい開発者
カスタムの初期ルートを使用すると、キャッシュされたルートを設定できますFlutterEngine
直前にカスタムの初期ルートを使用するには
Dart エントリポイントを実行します。次の例
キャッシュされたエンジンでの初期ルートの使用を示します。
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
// Instantiate a FlutterEngine.
flutterEngine = new FlutterEngine(this);
// Configure an initial route.
flutterEngine.getNavigationChannel().setInitialRoute("your/route/here");
// Start executing Dart code to pre-warm the FlutterEngine.
flutterEngine.getDartExecutor().executeDartEntrypoint(
DartEntrypoint.createDefault()
);
// Cache the FlutterEngine to be used by FlutterActivity or FlutterFragment.
FlutterEngineCache
.getInstance()
.put("my_engine_id", flutterEngine);
}
}
class MyApplication : Application() {
lateinit var flutterEngine : FlutterEngine
override fun onCreate() {
super.onCreate()
// Instantiate a FlutterEngine.
flutterEngine = FlutterEngine(this)
// Configure an initial route.
flutterEngine.navigationChannel.setInitialRoute("your/route/here");
// Start executing Dart code to pre-warm the FlutterEngine.
flutterEngine.dartExecutor.executeDartEntrypoint(
DartExecutor.DartEntrypoint.createDefault()
)
// Cache the FlutterEngine to be used by FlutterActivity or FlutterFragment.
FlutterEngineCache
.getInstance()
.put("my_engine_id", flutterEngine)
}
}
ナビゲーション チャネルの初期ルートを設定すると、関連付けられたFlutterEngine
の最初の実行時に目的のルートを表示します。runApp()
ダーツ機能。
ナビゲーションチャネルの初期ルートプロパティの変更
最初の実行後runApp()
効果はありません。
同じものを使用したい開発者FlutterEngine
異なる間Activity
砂Fragment
とスイッチ
これらのディスプレイ間のルートにはメソッド チャネルを設定する必要があります。
Dart コードに変更を明示的に指示するNavigator
ルート。
スプラッシュ画面を表示する
Flutterコンテンツの初期表示には多少の待ち時間がかかりますが、
あらかじめ温めておいたとしてもFlutterEngine
使用されている。
ユーザーエクスペリエンスを向上させるために
この短い待ち時間の間、Flutter は
Flutter までのスプラッシュ画面 (「起動画面」とも呼ばれます) の表示
最初のフレームをレンダリングします。打ち上げを表示する方法については、
画面を参照してください。スプラッシュスクリーンガイド。
指定された初期ルートで Flutter を実行する
Android アプリには、多数の独立した Flutter エクスペリエンスが含まれる場合があります。
さまざまな場所で実行されているFlutterFragment
s、異なるFlutterEngine
s.これらのシナリオでは、
各 Flutter エクスペリエンスは異なることから始まるのが一般的です
初期ルート(以外のルート)/
)。
これを容易にするために、FlutterFragment
のBuilder
以下に示すように、希望の初期ルートを指定できます。
// With a new FlutterEngine.
FlutterFragment flutterFragment = FlutterFragment.withNewEngine()
.initialRoute("myInitialRoute/")
.build();
// With a new FlutterEngine.
val flutterFragment = FlutterFragment.withNewEngine()
.initialRoute("myInitialRoute/")
.build()
指定したエントリポイントから Flutter を実行する
初期ルートを変えるのと似ていますが、異なります。FlutterFragment
別のことを実行することもできます
ダーツのエントリーポイント。一般的な Flutter アプリには、次のものが 1 つだけあります。
Dart エントリーポイント:main()
ですが、他のエントリポイントを定義することもできます。
FlutterFragment
希望の仕様をサポートします
指定された Flutter エクスペリエンスに対して実行する Dart エントリポイント。
エントリポイントを指定するには、次のようにビルドします。FlutterFragment
に示すように、
FlutterFragment flutterFragment = FlutterFragment.withNewEngine()
.dartEntrypoint("mySpecialEntrypoint")
.build();
val flutterFragment = FlutterFragment.withNewEngine()
.dartEntrypoint("mySpecialEntrypoint")
.build()
のFlutterFragment
構成の結果が実行される
という Dart エントリポイントのmySpecialEntrypoint()
。
括弧に注目してください()
それは
には含まれていませんdartEntrypoint
String
名前。
FlutterFragment
のレンダリングモード
コントロールFlutterFragment
どちらかを使用できますSurfaceView
それをレンダリングする
Flutter コンテンツ、またはTextureView
。
デフォルトはSurfaceView
、これは大幅に
よりもパフォーマンスに優れていますTextureView
。しかし、SurfaceView
Android の途中でインターリーブすることはできませんView
階層。
あSurfaceView
どちらかが最下位である必要がありますView
階層構造の中で、
または一番上のView
階層内で。
さらに、Android N より前の Android バージョンでは、SurfaceView
レイアウトとレンダリングが異なるためアニメーション化できません
残りの部分と同期していませんView
階層。
これらのユースケースのいずれかがアプリの要件である場合、
それなら使う必要がありますTextureView
それ以外のSurfaceView
。
を選択TextureView
を構築することでFlutterFragment
とともにtexture
RenderMode
:
// With a new FlutterEngine.
FlutterFragment flutterFragment = FlutterFragment.withNewEngine()
.renderMode(FlutterView.RenderMode.texture)
.build();
// With a cached FlutterEngine.
FlutterFragment flutterFragment = FlutterFragment.withCachedEngine("my_engine_id")
.renderMode(FlutterView.RenderMode.texture)
.build();
// With a new FlutterEngine.
val flutterFragment = FlutterFragment.withNewEngine()
.renderMode(FlutterView.RenderMode.texture)
.build()
// With a cached FlutterEngine.
val flutterFragment = FlutterFragment.withCachedEngine("my_engine_id")
.renderMode(FlutterView.RenderMode.texture)
.build()
示されている構成を使用すると、結果は次のようになります。FlutterFragment
UI をTextureView
。
FlutterFragment
透明感のある
を表示しますデフォルトでは、FlutterFragment
不透明な背景でレンダリングします。
を使ってSurfaceView
。 (「制御」を参照)FlutterFragment
のレンダリング
モードではないピクセルの背景は黒になります。
flutterによって描かれました。不透明な背景でレンダリングすると、
パフォーマンス上の理由から優先されるレンダリング モード。
Android で透明度を使用した flutter レンダリングが否定的になる
パフォーマンスに影響します。ただし、デザインもたくさんありますが、
Flutter エクスペリエンスでは透明なピクセルが必要です。
基盤となる Android UI まで表示されます。このために、
Flutter は半透明をサポートします。FlutterFragment
。
の透明性を有効にするにはFlutterFragment
、
次の構成でビルドします。
// Using a new FlutterEngine.
FlutterFragment flutterFragment = FlutterFragment.withNewEngine()
.transparencyMode(FlutterView.TransparencyMode.transparent)
.build();
// Using a cached FlutterEngine.
FlutterFragment flutterFragment = FlutterFragment.withCachedEngine("my_engine_id")
.transparencyMode(FlutterView.TransparencyMode.transparent)
.build();
// Using a new FlutterEngine.
val flutterFragment = FlutterFragment.withNewEngine()
.transparencyMode(FlutterView.TransparencyMode.transparent)
.build()
// Using a cached FlutterEngine.
val flutterFragment = FlutterFragment.withCachedEngine("my_engine_id")
.transparencyMode(FlutterView.TransparencyMode.transparent)
.build()
FlutterFragment
そしてそのActivity
間の関係一部のアプリは使用を選択しますFragment
Android 画面全体として。
これらのアプリでは、Fragment
に
Androidのステータスバーのようなコントロールシステムクロム、
ナビゲーション バーと方向。
他のアプリでは、Fragment
は単に表すために使用されます
UIの一部。あFlutterFragment
慣れているかもしれない
引き出しの内部、ビデオプレーヤー、
またはシングルカード。このような状況では、次のようになります。
にとって不適切なbcbd389-4a45-459f-952f-a8d288ed4740影響する
他にもUIがあるのでAndroidのシステムクローム
同じ内の部分Window
。
FlutterFragment
役立つコンセプトが付属しています
の場合を区別します。FlutterFragment
ホストを制御できるはずですActivity
、 そしてその
場合FlutterFragment
影響を与えるだけである必要があります
自分自身の行動。を防ぐにはFlutterFragment
から
それを暴露するActivity
Flutter プラグイン、および
Flutter による制御を防ぐActivity
のシステム UI、
使用shouldAttachEngineToActivity()
のメソッドFlutterFragment
のBuilder
に示すように、
// Using a new FlutterEngine.
FlutterFragment flutterFragment = FlutterFragment.withNewEngine()
.shouldAttachEngineToActivity(false)
.build();
// Using a cached FlutterEngine.
FlutterFragment flutterFragment = FlutterFragment.withCachedEngine("my_engine_id")
.shouldAttachEngineToActivity(false)
.build();
// Using a new FlutterEngine.
val flutterFragment = FlutterFragment.withNewEngine()
.shouldAttachEngineToActivity(false)
.build()
// Using a cached FlutterEngine.
val flutterFragment = FlutterFragment.withCachedEngine("my_engine_id")
.shouldAttachEngineToActivity(false)
.build()
通過false
にshouldAttachEngineToActivity()
Builder
メソッドは Flutter との対話を防ぎます。
周囲のActivity
。デフォルト値は次のとおりですtrue
、
これにより、Flutter および Flutter プラグインが
周囲のActivity
。